package basics.cankao;

import basics.annotation.AParameter;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

/**
 * @author Ldanniel
 * @description :
 * @date 2022/11/01 22:31
 * @since open jdk 1.8
 */

public class Addition {
    private static final Gson gson;
    private static final Type type;

    static {
        gson = new GsonBuilder().create();
        // 可以得到带有泛型的map类型
        type = new TypeToken<Map<String, String>>() {}.getType();
    }

    /**
     * 执行反射
     * @param action
     * @param parameter
     * @return
     * @throws Exception
     */
    public String doRequest(String action, String parameter) throws Exception {
        ActionDefination ad = ActionFactory.newInstance().getActionDefination(action);

        if (ad == null) {
            throw new ActionNotDefineException("方法" + action + "未定义！");
        }

        Object object = ad.getObject();
        Method method = ad.getMethod();

        if (parameter != null) {
            Object[] parameters = getParameterArr(parameter, ad.getParamerterList());
            Object result = method.invoke(object, parameters);
            return gson.toJson(result);
        }

        return null;

    }

    private Object[] getParameterArr(String parameterString, List<Parameter> parameterList) {
        Object[] results = new Object[parameterList.size()];
        // 将字符串形式的参数，转换成map
        Map<String, String> parameterStringMap = gson.fromJson(parameterString, type);

        int index = 0;
        for (Parameter parameter : parameterList) {
            // 得到参数的注解AParameter中name的值
            Object key = parameter.getAnnotation(AParameter.class).name();

            // 以name的值为键，找到参数map中value，再通过gson将其从字符串转换成具体的对象
            Object value = gson.fromJson(parameterStringMap.get(key),
                    // 得到参数的具体类型
                    parameter.getParameterizedType());

            results[index++] = value;
        }

        return results;
    }
}